﻿using SuperKit;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SuperKit {

    public class DirectoryExecutor {
        public IExecutorOwner Parent { get; }
        public string MainDir { get; }

        public int SyncCount { get; }
        public List<DirectoryExecutorItem> Dirs { get; set; }

        public DirectoryExecutor(string dir, IExecutorOwner owner) {
            Parent = owner;
            MainDir = dir;
            SyncCount = owner.GetMaxShellCount();
            Dirs = new List<DirectoryExecutorItem>();
        }

        public void Execute() {
            Dirs.Clear();
            Add(MainDir);
            StartThread();
        }


        public void Add(string dir) {
            var item = new DirectoryExecutorItem(dir, this);
            item.Index = Dirs.Count;
            Dirs.Add(item);
        }


        public void ExecuteSub() {
            Dirs.Clear();
            DirectoryInfo dir = new DirectoryInfo(MainDir);
            var dirs = dir.GetDirectories();
            if (dirs != null) {
                foreach (var i in dirs) {
                    Add(i.FullName);
                }
                StartThread();
            } else {
                Parent.Title($"项目({0}/{0}) - 全部完成");
            }            
        }

        public bool IsAllComplete {
            get {
                foreach (var i in Dirs) {
                    if (i.Status != DirectoryExecutorItem.COMPLETE) {
                        return false;
                    }
                }
                return true;
            }
        }

        public int RunningCount => GetCount(DirectoryExecutorItem.EXECUTE);
        public int ReadyCount => GetCount(DirectoryExecutorItem.READY);
        public int CompleteCount => GetCount(DirectoryExecutorItem.COMPLETE);

        public int GetCount(int status) {
            int count = 0;
            foreach (var i in Dirs) {
                if (i.Status == status) {
                    count++;
                }
            }
            return count;
        }

        private DirectoryExecutorItem PickReady() {
            foreach (var i in Dirs) {
                if (i.Status == DirectoryExecutorItem.READY) {
                    return i;
                }
            }
            return null;
        }

        private void StartThread() {
            RefreshLog();
            Thread t = new Thread(OnRunning);
            t.Start();
        }

        private void RefreshLog() {
            Parent.RefreshLog();
        }

        private void OnRunning() {
            while (true) {
                if (IsAllComplete) {
                    break;
                }
                if (RunningCount < SyncCount) {
                    ExecuteNew();
                }
                Thread.Sleep(ConfigReader.Instance.GetInt("SleepTime", 10));
                Parent.Title($"项目({CompleteCount}/{Dirs.Count}) - 进行:{RunningCount}");
            }
            Parent.Title($"项目({CompleteCount}/{Dirs.Count}) - 全部完成");
        }

        private void ExecuteNew() {
            var item = PickReady();
            if (item == null) return;

            // 这个需要放在执行前，因为如果放在执行后LogIndex会在Shell发送出去
            item.Status = DirectoryExecutorItem.EXECUTE;
            RefreshExecuteIndex();

            if (Parent.IsUseShell()) {
                Parent.StartUdpServer();
                item.ExecuteShell();
            } else {
                item.Execute();
            }
            
        }

        private bool IsUsed(List<int> list, int id) {
            foreach (var i in list) {
                if (i == id) {
                    return true;
                }
            }
            return false;
        }

        private int PickUnusedIndex(List<int> list) {
            for (int i = 0; i < 100; i++) {
                if (IsUsed(list, i) == false) {
                    return i;
                }
            }
            return 0;
        }

        private void RefreshExecuteIndex() {
            List<int> usedIndex = new List<int>();
            foreach (var i in Dirs) {
                if (i.Status == DirectoryExecutorItem.EXECUTE) {
                    if (i.LogIndex == 0) {
                        i.LogIndex = PickUnusedIndex(usedIndex);
                    }
                    usedIndex.Add(i.LogIndex);
                }
            }
        }
    }
}
